//#include <math.h>
#include <cutil.h>
#include <Particula.h>
#include <vector_types.h>

__constant__ float constGas = 5;
__constant__ float coeficienteViscosidade = 0.001;


__device__ float CalculaKernelME(float3 posParticula, float3 posVizinho, float h) {

        
        float squarePart1 = (posParticula.x - posVizinho.x);
        float squarePart2 = squarePart1 * squarePart1;
        float squarePart3 = (posParticula.y - posVizinho.y);
        float squarePart4 = squarePart3 * squarePart3;
        float squarePart5 = squarePart2 + squarePart4;
        float distancia = sqrt(squarePart5); //sqrtf(((VBO[indiceParticula].x - VBO[posicaoParticula].x) * (VBO[indiceParticula].x - VBO[posicaoParticula].x)) + (((VBO[indiceParticula].y - VBO[posicaoParticula].y) * (VBO[indiceParticula].y - VBO[posicaoParticula].y))));
             
		float massaEspecifica = 0.0f;
			   		
        //CALCULO DA MASSA ESPECIFICA.
        if (distancia < h) {
			massaEspecifica = distancia; 
            //particulas2[posicaoParticula].massaEspecifica = particulas[indiceParticula].massaEspecifica * ((315 / (64 * 3.14 * __powf(h, 9))));// * __powf((h*h - distancia*distancia), 3);
        }
	return massaEspecifica;
}

__global__ void FindNeighbors(float3* VBO, Particula* particulas, Particula* particulas2, unsigned int* values, unsigned int* keys,
        unsigned int* count, unsigned int* offSet, int numeroColunasGridCell, int numeroLinhasGridCell, const int numeroParticulas,
        float deltaX, float deltaY, float XminGrid, float YminGrid, float massaEspecificaInicial, float massa) {

    int thread = threadIdx.x;
    int block = blockIdx.x;
    int dim = blockDim.x;
    int indiceValue = dim * block + thread;
    int jAtual = 0;
    int iAtual = 0;
    int jMin = 0;
    int jMax = numeroColunasGridCell;
    int iMin = 0;
    int iMax = numeroLinhasGridCell;
    int idCell = 0;
    int kInicial = 0;
    int kFinal = 0;
    float h = deltaY;
    if (deltaX < deltaY) {
        h = deltaX;
    }


    if (indiceValue < numeroParticulas) {
        int posicaoParticula = values[indiceValue];
        jAtual = (VBO[posicaoParticula].x / deltaX);
        iAtual = (VBO[posicaoParticula].y / deltaY);
        //int idCellAtual = (iAtual * numeroColunasGridCell) + jAtual;

        //VERIFICAO DAS EXTREMIDADES.
        if (jAtual == 0) {
            jMin = 0;
        } else {
            jMin = jAtual - 1;
        }

        if (jAtual == (numeroColunasGridCell - 1)) {
            jMax = jAtual;
        } else {
            jMax = jAtual + 1;
        }

        if (iAtual == 0) {
            iMin = 0;
        } else {
            iMin = iAtual - 1;
        }

        if (iAtual == (numeroLinhasGridCell - 1)) {
            iMax = iAtual;
        } else {
            iMax = iAtual + 1;
        }


        for (int i = iMin; i <= iMax; i++) {
            for (int j = jMin; j <= jMax; j++) {
                idCell = (i * numeroColunasGridCell) + j;

                kInicial = offSet[idCell];
                kFinal = count[idCell];

                for (int k = 0; k < 3 /*numeroParticulas*/; k++) 
				
					if ( k < kFinal ) {
				
	                    int indiceParticula = values[kInicial + k];
						
						particulas2[posicaoParticula].massaEspecifica = CalculaKernelME(VBO[indiceParticula], VBO[posicaoParticula], h);
					
//            	    if(k > count[idCell])
  //              	   break;
					
                		}
            }
        }
    }
}

extern "C" void launch_FindNeighbors(unsigned int blocksPerGrid, unsigned int threadsPerBlock,
        float3* posicoes, Particula* particulas, Particula* particulas2, unsigned int* values, unsigned int* keys,
        unsigned int* count, unsigned int* offSet, int numeroColunasGridCell, int numeroLinhasGridCell, const int numeroParticulas,
        float deltaX, float deltaY, float XminGrid, float YminGrid, float massaEspecificaInicial, float massa) {
    // execute the kernel
    FindNeighbors <<<blocksPerGrid, threadsPerBlock>>>(posicoes, particulas, particulas2, values, keys, count, offSet, numeroColunasGridCell, numeroLinhasGridCell, numeroParticulas, deltaX, deltaY, XminGrid, YminGrid, massaEspecificaInicial, massa);
}


